package com.benmei.weike.web;

import com.benmei.weike.common.Constants;
import com.benmei.weike.common.GoodsCategory;
import com.benmei.weike.common.Lang;
import com.benmei.weike.common.PayType;
import com.benmei.weike.dto.PageRequest;
import com.benmei.weike.dto.PageResponse;
import com.benmei.weike.dto.payment.CreateOrderRequest;
import com.benmei.weike.entity.Bill;
import com.benmei.weike.entity.SystemAccessLog;
import com.benmei.weike.exception.ClientException;
import com.benmei.weike.service.PaymentService;
import com.benmei.weike.service.common.MemcachedService;
import com.benmei.weike.util.IPUtil;
import com.benmei.weike.util.JsonUtil;
import com.nativetalk.base.RetInfo;
import com.nativetalk.bean.member.TdNtMember;
import com.pingplusplus.model.Charge;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.IntrospectionException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.*;

/**
 * 学生端 微课接口
 */
@RestController
@RequestMapping(value = "/payment")
public class PaymentController {

    public static final Logger logger = LoggerFactory.getLogger(PaymentController.class);

    @Autowired
    private MemcachedService memcachedService;

    @Autowired
    private PaymentService paymentService;


    //log 记录方法入惨的前缀
    private static final String prefix_in = "\nparameters in -->> ";
    //log 记录方法出惨的前缀
    private static final String prefix_out = "\nparameters out -->>";


    @RequestMapping(value = "/token/create/order", method = {RequestMethod.POST})
    @ResponseBody
    public RetInfo studentCreateOrder(HttpServletRequest request, @RequestBody CreateOrderRequest req, @RequestHeader(value = "token") String token) {
        try {
            logger.info(prefix_in + JsonUtil.toJson(req));
            //校验token，如果校验通过就从缓存中读取Member
            if (StringUtils.isBlank(token)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("Parameter token  is required");
                logger.info(JsonUtil.toJson(retInfo));
                return retInfo;
            }
            Object o = memcachedService.get(token);
            if (o == null) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存中没有MemberToken:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }

            if (!TdNtMember.class.isInstance(o)) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存的token不是TdNtMember类型:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }
            TdNtMember tdNtMember = (TdNtMember) o;

            // 一 、商品类别相关校验
            if (StringUtils.isBlank(req.getGoodsCategoryCode())) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("商品类别不能为空");
                logger.info(JsonUtil.toJson(retInfo) + "，goodsCategoryCode:" + req.getGoodsCategoryCode());
                return retInfo;
            }
            if (!GoodsCategory.contains(req.getGoodsCategoryCode())) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("无效的商品类别");
                logger.info(JsonUtil.toJson(retInfo) + "，goodsCategoryCode:" + req.getGoodsCategoryCode());
                return retInfo;
            }

            // 充值
            if (GoodsCategory.RECHARGE.getCode().equals(req.getGoodsCategoryCode())) {

                // 1 充值金额必须大于0
                if (req.getMoney() == null || req.getMoney().compareTo(new BigDecimal(0)) <= 0) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("充值金额必须大于0");
                    logger.info(JsonUtil.toJson(retInfo) + "，money:" + req.getMoney());
                    return retInfo;
                }

                // 2 充值不能呢使用余额支付，不能使用混合支付
                if (PayType.WALLET.equals(req.getPayType()) || PayType.MULTIPLE.equals(req.getPayType())) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("充值必须使用第三方支付");
                    logger.info(JsonUtil.toJson(retInfo) + "，PayType:" + req.getPayType());
                    return retInfo;
                }
            }

            // 二、支付类型校验：wallet、multiple、thirdpart
            // 校验payType
            String payType = req.getPayType();
            if (StringUtils.isBlank(payType)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("支付类型不能为空");
                logger.info(JsonUtil.toJson(retInfo) + " payType:" + payType);
                return retInfo;
            }
            if (!PayType.contains(payType)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("无效的支付类型");
                logger.info(JsonUtil.toJson(retInfo) + " payType:" + payType);
                return retInfo;
            }

            // 如果是第三方支付或混合支付，那么支付渠道不能为空，并且不能随意写
            if (payType.equals(PayType.THIRDPART) || payType.equals(PayType.MULTIPLE)) {
                String payChannel = req.getChannel();
                if (StringUtils.isBlank(payChannel)) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("支付渠道不能为空");
                    logger.info(JsonUtil.toJson(retInfo) + " channel:" + payChannel);
                    return retInfo;
                }
                if (!payChannel.equals(Constants.PaymentChannel.alipay_name) && !payChannel.equals(Constants.PaymentChannel.wxpay_name) && !payChannel.equals(Constants.PaymentChannel.paypal_name)) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("支付渠道错误：支付渠道只能是alipay或wx,paypal");
                    logger.info(JsonUtil.toJson(retInfo) + " channel:" + payChannel);
                    return retInfo;
                }
                if(payChannel.equals(Constants.PaymentChannel.paypal_name) && StringUtils.isBlank(req.getPaypalId())){
                    RetInfo retInfo = RetInfo.getClientErrorInfo("paypal支付失败：paypalId不能为空");
                    logger.info(JsonUtil.toJson(retInfo) + " paypalId:" + req.getPaypalId());
                    return retInfo;
                }
            }

            RetInfo retInfo = paymentService.studentCreateOrder(req, tdNtMember.getMemb_id(), IPUtil.getIp(request));

            logger.info(prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (ClientException e) {
            logger.error(e.getMessage(), e);
            RetInfo retInfo = RetInfo.getClientErrorInfo(e.getMessage());
            logger.error(prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            RetInfo retInfo = RetInfo.getServerErrorInfo();
            logger.error(prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        }
    }

    /**
     * @return RetInfo
     * @Purpose Ping++ WebHooks异步通知
     * @version 1.0
     * @time 2015-01-06
     * @author Peter
     */
    @RequestMapping(value = "/pay/notify", method = {RequestMethod.GET,RequestMethod.POST}, consumes = "application/json")
    public void notify(@RequestBody Map<String, Object> params, HttpServletRequest request, HttpServletResponse response) {
        try {
            //打印入参
            logger.info("\nPing++ WebHooks异步通知 -->>\n" + Constants.prefix_in + JsonUtil.toJson(params));
            request.setCharacterEncoding("UTF8");
            paymentService.notify(params);
            response.setStatus(200);
            //打印出参
        } catch (Exception e) {
            //记录错误日志
            RetInfo retInfo = RetInfo.getServerErrorInfo();
            logger.error(e.getMessage(), e);
            //打印出参
            logger.error(Constants.prefix_out + JsonUtil.toJson(retInfo));
            response.setStatus(500);
        }
    }

    /**
     * @return RetInfo
     * @Purpose 我的钱包
     * @version 1.0
     * @time 2015-01-06
     * @author lizhun
     */
    @RequestMapping(value = "/token/student/wallet", method = {RequestMethod.POST}, consumes = "application/json")
    @ResponseBody
    public RetInfo wallet(@RequestBody PageRequest req, @RequestHeader(value = "token") String token) {
        try {
            //打印入参
            logger.info("\n" + Constants.prefix_in + JsonUtil.toJson(req));

            //校验token，如果校验通过就从缓存中读取Member
            if (StringUtils.isBlank(token)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("Parameter token  is required");
                logger.info(JsonUtil.toJson(retInfo));
                return retInfo;
            }
            Object o = memcachedService.get(token);
            if (o == null) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存中没有MemberToken:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }

            if (!TdNtMember.class.isInstance(o)) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存的token不是TdNtMember类型:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }
            TdNtMember tdNtMember = (TdNtMember) o;

            PageResponse response = paymentService.wallet(req, tdNtMember.getMemb_id());
            BigDecimal balance = paymentService.getBalance(tdNtMember.getMemb_id());
            //打印出参
            RetInfo retInfo = RetInfo.getSuccessInfo("查询账单成功");

            Map<String,Object> map = new HashMap<>();
            map.put("bills",response);
            map.put("balance",balance);
            retInfo.setObj(map);
            logger.info(prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (Exception e) {
            //记录错误日志
            RetInfo retInfo = RetInfo.getServerErrorInfo();
            //打印出参
            logger.error(Constants.prefix_out + JsonUtil.toJson(retInfo), e);

            return retInfo;
        }
    }


}
